#!/usr/bin/ruby

require 'rubygems'
require 'pp'
require 'xmlrpc/client'
require 'optparse'
require 'yaml' 
require 'base64' ## required for downloading attachments 

## hash for all the options
options = {}
options[:username] = ""
options[:password] = ""
options[:project] = ""
options[:server] = ""
options[:filename] = ""

## Get options from YAML
## 
CONFIG = YAML::load(File.read('../settings/options.yaml'))
options[:username] = CONFIG['settings']['username']
options[:password] = CONFIG['settings']['password']
options[:project] = CONFIG['settings']['project']
options[:server] = CONFIG['settings']['server']
options[:filename] = CONFIG['settings']['filename']

## Set up the option parser
optparse = OptionParser.new do|opts|
   opts.banner = "Usage: ticketgen.rb --user [user] --pass [pass] --project [project] --server [server] --filename [ticketfile]" 

   ## Gather command-line options
   opts.on('-h', '--help', 'Help Screen') do
      puts opts
      exit
   end
   
   opts.on('-v', '--verbose', 'Verbose Output') do
      options[:verbose] = true
      exit
   end

   opts.on('-u', '--user USER', String, 'Trac Username') do |username|
      options[:username]  = username
   end

   opts.on('-p', '--password PASSWORD', String, 'Trac Password') do |password|
      options[:password]  = password
   end  

   opts.on('-r', '--project PROJECT', String, 'Trac Project') do |project|
      options[:project]  = project
   end

   opts.on('-s', '--server SERVER', String, 'Trac Server') do |server|
      options[:server]  = server
   end
 
   opts.on('-f', '--filename FILENAME', String, 'Trac Tickets (filename)') do |filename|
      options[:filename] = filename
   end
end


# Parse the command-line. Remember there are two forms
# of the parse method. The 'parse' method simply parses
# ARGV, while the 'parse!' method parses ARGV and removes
# any options found there, as well as any parameters for
# the options. What's left is the list of files to resize.
optparse.parse!


## Gather interactively if not specified
if options[:username].to_s.empty? then
   puts "User:"
   options[:username] = gets
end

if options[:password].to_s.empty? then
   puts "Password:"
   options[:password] = gets
end

if options[:project].to_s.empty? then
   puts "Project:"
   options[:project] = gets
end

if options[:server].to_s.empty? then
   puts "Server:"
   options[:server] = gets
end

if options[:filename].to_s.empty? then
   puts "Filename:"
   options[:filename] = gets
end

## ensure we have strings
String username = options[:username]
String password = options[:password]
String server = options[:server]
String project = options[:project]


## remove newlines
username.chomp!
password.chomp!
server.chomp!
project.chomp!


def get_attachment(server, ticketnum,filename)

   ## call server method
   x = server.call("ticket.getAttachment", ticketnum, filename) ##returns the content of an attachment.

   return x
end

def get_attachments(server,ticketnum, project)
   someArray = server.call("ticket.listAttachments", ticketnum) ##Lists attachments for a given ticket.
   
   if (!someArray.empty?) then

     names =  Array.new
     ## get this particular attachment 
     someArray.each { |attachment|
	
	## filename should be the first parameter
	filename = attachment[0]
         
         ## store this for xml
         names.push filename

	## get the attachment
	x = get_attachment(server, ticketnum,filename)

	## Create a directory for this file
	Dir.mkdir(project + "/" + ticketnum.to_s) unless File.directory?(project + "/" + ticketnum.to_s)

	## save the file	
  	myfile = File.new(project + "/" + ticketnum.to_s + "/" + filename, "w+")
	myfile.write(x)
      }
   end

   return names ## for xml
end

def get_ticket(server, ticketnum, project)
   # print the data
   results = server.call("ticket.get",ticketnum)

##   puts "Ticket: " + results[3]["summary"].to_s

   ## get the shiz 
   title = results[3]["summary"].to_s ## or something?
   reporter = results[3]["reporter"].to_s
   owner = results[3]["owner"].to_s
   description = results[3]["description"].to_s
   type = results[3]["type"].to_s
   status = results[3]["status"].to_s
   priority = results[3]["priority"].to_s
   milestone = results[3]["milestone"].to_s
   component = results[3]["component"].to_s
   version = results[3]["version"].to_s
   resolution = results[3]["resolution"].to_s
   keywords = results[3]["keywords"].to_s
   ccname = results[3]["ccname"].to_s
   templatefinding = results[3]["templatefinding"].to_s
   damagePotential = results[3]["damagepotential"].to_s
   reproducibility = results[3]["reproducibility"].to_s
   exploitability = results[3]["exploitability"].to_s
   affectedUsers = results[3]["affectedusers"].to_s
   discoverability = results[3]["discoverability"].to_s
   proof = results[3]["proof"].to_s
   recommendations = results[3]["recommendations"].to_s
   references = results[3]["references"].to_s
   remediationEffort = "undefined"
   affects = "undefined"

   ## calculate dread total
   dreadTotal = damagePotential.to_i + 
		reproducibility.to_i + 
		exploitability.to_i + 
		affectedUsers.to_i + 
		discoverability.to_i

   ## calculate dread risk
   ## calculate dread risk
   dreadRisk = "undefined"
   if (dreadTotal > 40) then
        dreadRisk = "Critical"
   elsif (dreadTotal > 29)  
        dreadRisk = "Severe"
   elsif (dreadTotal > 10)
        dreadRisk = "Moderate"
   else
        dreadRisk = "Low"
   end

   ticket_matrix_string = ticketnum.to_s + "," +
        component + "," +
        title + "," +
        damagePotential + "," +
        reproducibility + "," +
        exploitability + "," +
        affectedUsers + "," +
        discoverability + "," +
        dreadTotal.to_s + "," +
        dreadRisk

   puts ticket_matrix_string + "\n" ## good for user feedback


   ## create project directory:
   Dir.mkdir(project) unless File.directory?(project)

   ## save the ticket to the matrix file
   myfile = File.new(project + "/ticket_matrix.csv", "a")
   myfile.write(ticket_matrix_string + "\n")
   

   ## iterate through attachments
   attachment_names = Array.new
   attachment_names = Array(get_attachments(server,ticketnum,project))

   ## create XML
   finding_xml = "   <finding number=\"" + ticketnum.to_s + "\">" +  "\n"
   finding_xml = finding_xml + "      <title>" + title + "</title>" + "\n"
   finding_xml = finding_xml + "      <status>"  + "verified" + "</status>" + "\n"
   finding_xml = finding_xml + "      <rating>" + "\n"
   finding_xml = finding_xml + "         <dread>" + "\n"
   finding_xml = finding_xml + "            <discoverability>" + discoverability + "</discoverability>" + "\n"
   finding_xml = finding_xml + "            <reproducibility>" + reproducibility + "</reproducibility>" + "\n"
   finding_xml = finding_xml + "            <exploitability>" + exploitability + "</exploitability>" + "\n"
   finding_xml = finding_xml + "            <affectedusers>" + affectedUsers + "</affectedusers>" + "\n"
   finding_xml = finding_xml + "            <damagepotential>" + damagePotential + "</damagepotential>" + "\n"
   finding_xml = finding_xml + "            <dreadtotal>" + dreadTotal.to_s + "</dreadtotal>" + "\n"
   finding_xml = finding_xml + "            <dreadrisk>" + dreadRisk + "</dreadrisk>" + "\n"
   finding_xml = finding_xml + "         </dread>" + "\n"
   finding_xml = finding_xml + "         <remediationeffort>" + remediationEffort + "</remediationeffort>" + "\n"
   finding_xml = finding_xml + "      </rating>" + "\n"
   finding_xml = finding_xml + "      <affects>" +  affects + "</affects>" + "\n"

   ##finding_xml = finding_xml + "      <prerequisites>" + "\n"
   ## iterate thru prerequisites
   ##   finding_xml = finding_xml + "         <prerequisite> " + prerequsite[x] + "</prerequsite>" + "\n"
   ##finding_xml = finding_xml + "      </prerequisites>" + "\n"

   finding_xml = finding_xml + "      <description>" + description + "</description>" + "\n"
   finding_xml = finding_xml + "      <proof>" + proof + "</proof>" + "\n"
   finding_xml = finding_xml + "      <recommendations>" + recommendations + "</recommendations>" + "\n"
   finding_xml = finding_xml + "      <references>" + references + "</references>" + "\n"
   finding_xml = finding_xml + "      <attachments>" + "\n"
   
   ## iterate thru attachments
   if (!attachment_names.empty?) then
     attachment_names.each { |name| 
        finding_xml = finding_xml + "         <attachment>" + name + "</attachment>" + "\n"
     }
   end

   finding_xml = finding_xml + "      </attachments> " + "\n"
   finding_xml = finding_xml + "   </finding>" + "\n"


   ## if we're doing singles:
   finding_xml = "<findings>\n" + finding_xml
   finding_xml = finding_xml + "</findings>"
   
   ## Create a directory for this file
   Dir.mkdir(project + "/" + ticketnum.to_s) unless File.directory?(project + "/" + ticketnum.to_s)

   ## save the file	
   myfile = File.new(project + "/" + ticketnum.to_s + "/" + "finding.xml", "w+")
   myfile.write(finding_xml)

  return finding_xml
end

## construct the project url
url = "https://" + username + ":" + password + "\@" + server + "/projects/" + project + "/xmlrpc"

##puts "DEBUG: URL: " + url + "\n\n\n"

# initialize the connection (username and password can be ommitted if not needed, but most of the time you will need them if anonymous doesn't have XMLRPC permissions)
server = XMLRPC::Client::new2(url)
x = server.call("ticket.query", "type=finding")
puts "no tickets" if x.empty?

##xml = "<findings>\n"
x.each { |ticketnum| get_ticket(server,ticketnum, project) }
##xml = xml + "</findings>\n"
##puts xml

puts "end.\n"
